import { _t } from "@web/core/l10n/translation";
import { registry } from "@web/core/registry";
import { EditMenuDialog } from "@website/components/dialog/edit_menu";
import { OptimizeSEODialog } from "@website/components/dialog/seo";
import { PagePropertiesDialog } from "@website/components/dialog/page_properties";

/**
 * This service displays contextual menus, depending of the state of the
 * website. These menus are defined in xml with the "website_preview" action,
 * which is overriden here for displaying dialogs, or regular components that
 * are not client actions.
 */
export const websiteCustomMenus = {
    dependencies: ["website", "orm", "dialog", "ui"],
    start(env, { website, orm, dialog, ui }) {
        const services = { website, orm, dialog, ui };
        return {
            get(xmlId) {
                return registry.category("website_custom_menus").get(xmlId, null);
            },
            async open(customMenu) {
                const menuConfig = this.get(customMenu.xmlid);
                if (menuConfig.openWidget) {
                    return menuConfig.openWidget(services);
                }
                const menuProps = {
                    ...(menuConfig.getProps && (await menuConfig.getProps(services))),
                    // Values on 'dynamicProps' are retrieved after the content is loaded (e.g. id of
                    // the content menu to be edited).
                    ...customMenu.dynamicProps,
                };
                return dialog.add(menuConfig.Component, menuProps);
            },
            addCustomMenus(sections) {
                const filteredSections = [];
                for (const section of sections) {
                    const isWebsiteCustomMenu = !!this.get(section.xmlid);
                    const displayWebsiteCustomMenu =
                        isWebsiteCustomMenu &&
                        website.isRestrictedEditor &&
                        this.get(section.xmlid).isDisplayed(env);
                    if (!isWebsiteCustomMenu || displayWebsiteCustomMenu) {
                        let subSections = [];
                        if (section.childrenTree.length) {
                            subSections = this.addCustomMenus(section.childrenTree);
                        }
                        if (section.xmlid === "website.custom_menu_edit_menu") {
                            // Hack: this code will simulate an XML pre-configured navbar menuitem to edit each
                            // content menu found on the current page by duplicating one menuitem with
                            // different data (name, dialog props...). this will prevent breaking the current
                            // 'navbar menus' display system.
                            filteredSections.push(
                                ...website.currentWebsite.metadata.contentMenus.map(
                                    (menu, index) => ({
                                        ...section,
                                        name: _t("Edit %s", menu[0]),
                                        dynamicProps: { rootID: parseInt(menu[1], 10) },
                                        // Prevent a 't-foreach' duplicate key on menus template.
                                        id: `${section.id}-${index}`,
                                    })
                                )
                            );
                        } else {
                            filteredSections.push(
                                Object.assign({}, section, { childrenTree: subSections })
                            );
                        }
                    }
                }
                for (const section of filteredSections) {
                    section.childrenTree = section.childrenTree.filter(
                        // Exclude non-leaf node having no visible sub-element.
                        (tree) => !(tree.children.length && !tree.childrenTree.length)
                    );
                }
                return filteredSections;
            },
        };
    },
};
registry.category("services").add("website_custom_menus", websiteCustomMenus);

registry.category("website_custom_menus").add("website.menu_edit_menu", {
    Component: EditMenuDialog,
    isDisplayed: (env) =>
        !!env.services.website.currentWebsite &&
        env.services.website.isDesigner &&
        !env.services.website.currentWebsite.metadata.translatable,
});
registry.category("website_custom_menus").add("website.menu_optimize_seo", {
    Component: OptimizeSEODialog,
    isDisplayed: (env) =>
        env.services.website.currentWebsite &&
        env.services.website.isRestrictedEditor &&
        !!env.services.website.currentWebsite.metadata.canOptimizeSeo,
});
registry.category("website_custom_menus").add("website.menu_ace_editor", {
    openWidget: (services) => (services.website.context.showResourceEditor = true),
    isDisplayed: (env) =>
        env.services.website.currentWebsite &&
        env.services.website.currentWebsite.metadata.viewXmlid &&
        !env.services.ui.isSmall,
});
registry.category("website_custom_menus").add("website.menu_page_properties", {
    Component: PagePropertiesDialog,
    isDisplayed: (env) =>
        env.services.website.currentWebsite &&
        env.services.website.isDesigner &&
        !!env.services.website.currentWebsite.metadata.mainObject,
    getProps: async ({ orm, website }) => {
        const mainObject = website.currentWebsite.metadata.mainObject;
        const isPage = mainObject.model === "website.page";
        const model = isPage ? "website.page.properties" : "website.page.properties.base";
        const websiteId = website.currentWebsite.id;
        // Do not rely on window.location.pathname: while the editor boots it can
        // still be "/web" or even empty, which would give the dialog a wrong URL.
        // website.currentLocation already tracks the actual page (without the
        // language prefix), so we reuse it and fall back to the metadata path,
        // forcing a leading '/' for extra safety. This keeps the wizard working
        // even if the user opens it as soon as the builder loads.
        const getNormalizedPath = () => {
            let path = website.currentLocation;
            if (!path) {
                try {
                    path = new URL(website.currentWebsite.metadata.path).pathname;
                } catch {
                    path = website.currentWebsite.metadata.path || "/";
                }
            }
            if (path && !path.startsWith("/")) {
                path = `/${path}`;
            }
            return path || "/";
        };
        const recordValues = isPage
            ? {
                  target_model_id: mainObject.id,
                  website_id: websiteId,
              }
            : {
                  target_model_id: `${mainObject.model},${mainObject.id}`,
                  url: getNormalizedPath(),
                  website_id: websiteId,
              };
        return {
            resId: await orm.call(model, "create", [recordValues]),
            resModel: model,
            onRecordSaved: async (record) => {
                const page = isPage
                    ? (await orm.read("website.page", [mainObject.id], ["website_id", "url"]))[0]
                    : undefined;
                return website.goToWebsite({
                    websiteId: page?.website_id?.[0] ?? website.currentWebsite.id,
                    path: page?.url ?? website.currentWebsite.metadata.path,
                });
            },
        };
    },
});
registry.category("website_custom_menus").add("website.custom_menu_edit_menu", {
    Component: EditMenuDialog,
    // 'isDisplayed' === true => at least 1 content menu was found on the page. This
    // menuitem will be cloned (in 'addCustomMenus()') to edit every content menu using
    // the 'EditMenuDialog' component.
    isDisplayed: (env) =>
        env.services.website.currentWebsite &&
        env.services.website.currentWebsite.metadata.contentMenus &&
        env.services.website.currentWebsite.metadata.contentMenus.length,
});
